/**
 * @file wa_mask_draw.c
 * 
 */

/*********************
 *      INCLUDES
 *********************/

#include "wa_mask_draw.h"



/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

#define WA_FP_MAXCOUNT 12

/**********************
 *  STATIC PROTOTYPES
 **********************/

static void fp_draw_h_line(int x1, int y, int x2,wa_area* mask_p, wa_gui_color color) ;
static int fp_check_y_intersect(int y, int* px, wa_point* p_p1, wa_point* p_p2);
static void fp_add(int x);
static void fp_init(void);
static void fp_flush(int y,wa_area* mask_p, wa_gui_color color);
static void fp_addpoint(int x, int y, int y0, int y1, wa_area* mask_p, wa_gui_color color);
static int fp_get_prev_point_diffy(wa_point* p_p, int i,int count, int y0);


/**********************
 *  STATIC VARIABLES
 **********************/
 
static int WA_FP_Cnt;
static int _aX[WA_FP_MAXCOUNT];

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
 
 
/**
 * drawpiont
 * @param x
 * @param y
 * @param mask_p
 * @param color
 */

void wa_mask_drawpoint(int x, int y, wa_area* mask_p, wa_gui_color color)
{
	wa_point p;
	p.x=x;
	p.y=y;
	if(wa_area_is_point_on(mask_p,&p) == wa_ok)
	{
		wa_disp_drv_setpixel(x,y,color);
	}
}

/**
 * fill rect
 * @param x 
 * @param y 
 * @param width
 * @param height
 * @param mask_p
 * @param color
 */

void wa_mask_fillrect(int x, int y, int width, int height, wa_area* mask_p, wa_gui_color color)
{
	wa_area input;
	wa_area conn;
	input.x1=x;
	input.y1=y;
	input.x2=x+width-1;
	input.y2=y+height-1;
	if(wa_area_union(&conn,&input,mask_p) == wa_ok)
	{
		wa_disp_drv_fill(conn.x1,conn.y1,(conn.x2-conn.x1+1),(conn.y2-conn.y1+1),color);
	}
}

/**
 * clear
 */
void wa_mask_clear(void)
{
	wa_disp_drv_clear();
}

/**
 * update
 */
void wa_mask_update(int32_t x, int32_t y, int32_t width, int32_t height)
{
	wa_disp_drv_update(x, y, width, height);
}

/**
 * draw line
 * @param x1
 * @param y1
 * @param x2
 * @param y2
 * @param mask_p
 * @param color
 */
void wa_mask_drawline(int x1, int y1,int x2, int y2, wa_area* mask_p,wa_gui_color color)
{
	int t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 
	delta_x=x2-x1; //computed coordinate increment
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)
	{
		incx=1; //set step direction
	}
	else if(delta_x==0)
	{
		incx=0;//perpendicular line
		wa_mask_fillrect(x1,WA_MATH_MIN(y1,y2),1,(WA_MATH_MAX(y1,y2)-WA_MATH_MIN(y1,y2)+1),mask_p,color);
		return;
	}		
	else 
	{
		incx=-1;
		delta_x=-delta_x;
	} 
	if(delta_y>0)
	{
		incy=1;
	}		
	else if(delta_y==0)
	{
		incy=0;//horizontal line
		wa_mask_fillrect(WA_MATH_MIN(x1,x2),y1,(WA_MATH_MAX(x1,x2)-WA_MATH_MIN(x1,x2)+1),1,mask_p,color);
		return;
	}		
	else
	{
		incy=-1;
		delta_y=-delta_y;
	} 
	if( delta_x>delta_y)
	{
		distance=delta_x; //select the basic increment axes
	}		
	else 
	{
		distance=delta_y;
	}		
	for(t=0;t<=distance+1;t++ )//draw line putput
	{  
		wa_mask_drawpoint(uRow,uCol,mask_p,color);//draw point
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
}

/**
 * draw rect
 * @param x 
 * @param y 
 * @param width
 * @param height
 * @param mask_p
 * @param color
 */

void wa_mask_drawrect(int x1, int y1, int width, int height, wa_area* mask_p, wa_gui_color color)
{
	int x2,y2;
	x2=x1+width-1;
	y2=y1+height-1;
	wa_mask_drawline(x1,y1,x1,y2,mask_p,color);
	wa_mask_drawline(x1,y1,x2,y1,mask_p,color);
	wa_mask_drawline(x1,y2,x2,y2,mask_p,color);
	wa_mask_drawline(x2,y1,x2,y2,mask_p,color);
}

/**
 * draw polygon
 * @param p_p 
 * @param count 
 * @param mask_p
 * @param color 
 */

void wa_mask_drawpolygon(wa_point* p_p, int count, wa_area* mask_p, wa_gui_color color)
{
	int i;
	for(i=0;i<count-1;i++)
	{
		wa_mask_drawline((p_p+i)->x,(p_p+i)->y,(p_p+i+1)->x,(p_p+i+1)->y,mask_p,color);
	}
	wa_mask_drawline((p_p)->x,(p_p)->y,(p_p+count-1)->x,(p_p+count-1)->y,mask_p,color);
}

/**
 * draw circle
 * @param x 
 * @param y 
 * @param r 
 * @param mask_p 
 * @param color 
 */

void wa_mask_drawcircle(int x, int y, int r, wa_area* mask_p, wa_gui_color color)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //a marker to determine the position of the next point
	while(a<=b)
	{
		wa_mask_drawpoint(x+a,y-b,mask_p,color);             //5
 		wa_mask_drawpoint(x+b,y-a,mask_p,color);             //0           
		wa_mask_drawpoint(x+b,y+a,mask_p,color);             //4               
		wa_mask_drawpoint(x+a,y+b,mask_p,color);             //6 
		wa_mask_drawpoint(x-a,y+b,mask_p,color);             //1       
 		wa_mask_drawpoint(x-b,y+a,mask_p,color);             
		wa_mask_drawpoint(x-a,y-b,mask_p,color);             //2             
  		wa_mask_drawpoint(x-b,y-a,mask_p,color);             //7     	         
		a++;
		//use Bresenham  
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
}

/**
 * fill circle
 * @param x 
 * @param y 
 * @param r 
 * @param mask_p 
 * @param color 
 */

void wa_mask_fillcircle(int x, int y, int r, wa_area* mask_p, wa_gui_color color)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //a marker to determine the position of the next point
	while(a<=b)
	{
		wa_mask_drawline(x+a,y-b,x+a,y+b,mask_p,color);
		wa_mask_drawline(x+b,y-a,x+b,y+a,mask_p,color);
		wa_mask_drawline(x-a,y-b,x-a,y+b,mask_p,color);
		wa_mask_drawline(x-b,y-a,x-b,y+a,mask_p,color);
		
		a++;
		//use Bresenham    
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
}

/**
 * fill a polygon
 * @param p_p 
 * @param count
 * @param mask_p
 * @param color
 */
void wa_mask_fillpolygon(wa_point* p_p, int count, wa_area* mask_p, wa_gui_color color) 
{
	int i, y;
	int ymin = WA_LCD_H;
	int ymax = 0;
	/* First step : find uppermost and lowermost coordinates */
	for (i=0; i<count; i++) 
	{
		y = (p_p + i)->y;
		if (y < ymin)
		{
			ymin = y;
		}
		if (y > ymax)
		{
			ymax = y;
		}
	}
	/* Second step: Calculate and draw horizontal lines */
	for (y=ymin; y<=ymax; y++) 
	{
		fp_init();
		/* find next intersection and count lines*/
		for (i=0; i<count; i++) 
		{
			int i1 = (i < (count - 1)) ? i + 1 : 0;
			int y0 = (p_p + i )->y;
			int y1 = (p_p + i1)->y;
			/* Check if starting point is on line */
			if(y0 == y) 
			{
				if (y1 == y) 
				{  /* Add the entire line */
					fp_draw_h_line((p_p + i )->x, y, (p_p + i1)->x, mask_p,color);
				}
				else
				{        /* Add only one point */
					int yprev = fp_get_prev_point_diffy(p_p, i, count, y);
					if (yprev != y) 
					{
						fp_addpoint((p_p + i)->x, y, yprev - y, y1 - y, mask_p, color);
					} 
				}
			}
			else if (y1 != y)
			{  /* Ignore if end-point is on the line */
				if (((y1 >= y) && (y0 <= y)) || ((y0 >= y) && (y1 <= y)))
				{
					int xintersect;
					if (fp_check_y_intersect(y, &xintersect, p_p + i, p_p + i1))
					{
						fp_add(xintersect);
					}
				}
			}
		}
		fp_flush(y, mask_p, color);
	}  
}

/**
 * draw round rect
 * @param x1
 * @param y1
 * @param width
 * @param heighr
 * @param r
 * @param mask_p
 * @param color
 */
void wa_mask_drawroundrect(int x1, int y1, int width, int height, int r, wa_area* mask_p, wa_gui_color color)
{
	int x2, y2;
	int min_length;
	int cx, cy;
	int hl, wl;
	int a, b;
	int di;
	min_length = WA_MATH_MIN(width, height);
	if (r > (min_length / 2))
	{
		r = min_length / 2;
	}
	x2 = x1 + width - 1;
	y2 = y1 + height - 1;
	cx = x1 + r;
	cy = y1 + r;
	wl = width - 2 * r - 1;
	hl = height - 2 * r - 1;
	//draw four line
	wa_mask_drawline(x1 + r, y1, x2 - r, y1, mask_p, color);
	wa_mask_drawline(x1 + r, y2, x2 - r, y2, mask_p, color);
	wa_mask_drawline(x1, y1 + r, x1, y2 - r, mask_p, color);
	wa_mask_drawline(x2, y1 + r, x2, y2 - r, mask_p, color);
	//draw four round
	a = 0; b = r;
	di = 3 - (r << 1);             //a marker to determine the position of the next point
	while (a <= b)
	{
		wa_mask_drawpoint(cx + a + wl, cy - b, mask_p, color);           
		wa_mask_drawpoint(cx + b + wl, cy - a, mask_p, color); 

		wa_mask_drawpoint(cx + b + wl, cy + a + hl, mask_p, color);      
		wa_mask_drawpoint(cx + a + wl, cy + b + hl, mask_p, color);

		wa_mask_drawpoint(cx - a, cy + b + hl, mask_p, color);
		wa_mask_drawpoint(cx - b, cy + a + hl, mask_p, color);

		wa_mask_drawpoint(cx - a, cy - b, mask_p, color);
		wa_mask_drawpoint(cx - b, cy - a, mask_p, color);
		a++;
		//use Bresenham  
		if (di < 0)di += 4 * a + 6;
		else
		{
			di += 10 + 4 * (a - b);
			b--;
		}
	}
}

/**
 * fill round rect
 * @param x1
 * @param y1
 * @param width
 * @param heighr
 * @param r
 * @param mask_p
 * @param color
 */
void wa_mask_fillroundrect(int x1, int y1, int width, int height, int r, wa_area* mask_p, wa_gui_color color)
{
	int min_length;
	int cx, cy;
	int hl, wl;
	int a, b;
	int di;
	min_length = WA_MATH_MIN(width, height);
	if (r > (min_length / 2))
	{
		r = min_length / 2;
	}
	cx = x1 + r;
	cy = y1 + r;
	wl = width - 2 * r - 1;
	hl = height - 2 * r - 1;
	//fill rect
	wa_mask_fillrect(x1 + r, y1, wl, height, mask_p, color);
	//fill round
	a = 0; b = r;
	di = 3 - (r << 1);             //a marker to determine the position of the next point
	while (a <= b)
	{
		
		wa_mask_drawline(cx + a + wl, cy - b, cx + a + wl, cy + b + hl, mask_p, color);
		wa_mask_drawline(cx + b + wl, cy - a, cx + b + wl, cy + a + hl, mask_p, color);

		wa_mask_drawline(cx - a, cy + b + hl, cx - a, cy - b, mask_p, color);
		wa_mask_drawline(cx - b, cy + a + hl, cx - b, cy - a, mask_p, color);
		a++;
		//use Bresenham  
		if (di < 0)di += 4 * a + 6;
		else
		{
			di += 10 + 4 * (a - b);
			b--;
		}
	}
}

void wa_mask_drawtriangle(int x1, int y1, int width, int height, int dir, wa_area* mask_p, wa_gui_color color)
{
	int x2, y2;
	int tx[4] = { 0 }, ty[4] = { 0 };
	int size;
	x2 = x1 + width - 1;
	y2 = y1 + height - 1;
	if (dir == WA_MASK_DRAW_TRIA_LEFT)
	{
		tx[0] = x2;
		ty[0] = y1;
		tx[1] = x2;
		ty[1] = y2;
		size = height / 2 + height % 2 - 1;
		tx[2] = x1;
		ty[2] = y1 + size;
		tx[3] = x1;
		ty[3] = y2 - size;

	}
	else if (dir == WA_MASK_DRAW_TRIA_RIGHT)
	{
		tx[0] = x1;
		ty[0] = y1;
		tx[1] = x1;
		ty[1] = y2;
		size = height / 2 + height % 2 - 1;
		tx[2] = x2;
		ty[2] = y1 + size;
		tx[3] = x2;
		ty[3] = y2 - size;
	}
	else if (dir == WA_MASK_DRAW_TRIA_UP)
	{
		tx[0] = x1;
		ty[0] = y2;
		tx[1] = x2;
		ty[1] = y2;
		size = width / 2 + width % 2 - 1;
		tx[2] = x1 + size;
		ty[2] = y1;
		tx[3] = x2 - size;
		ty[3] = y1;
	}
	else if (dir == WA_MASK_DRAW_TRIA_DOWN)
	{
		tx[0] = x1;
		ty[0] = y1;
		tx[1] = x2;
		ty[1] = y1;
		size = width / 2 + width % 2 - 1;
		tx[2] = x1 + size;
		ty[2] = y2;
		tx[3] = x2 - size;
		ty[3] = y2;
	}
	wa_mask_drawline(tx[0], ty[0], tx[1], ty[1], mask_p, color);
	wa_mask_drawline(tx[2], ty[2], tx[0], ty[0], mask_p, color);
	wa_mask_drawline(tx[3], ty[3], tx[1], ty[1], mask_p, color);
}

void wa_mask_filltriangle(int x1, int y1, int width, int height, int dir, wa_area* mask_p, wa_gui_color color)
{
	int x2, y2;
	int tx[4] = { 0 }, ty[4] = { 0 };
	int size;
	wa_point point[4];
	x2 = x1 + width - 1;
	y2 = y1 + height - 1;
	if (dir == WA_MASK_DRAW_TRIA_LEFT)
	{
		tx[0] = x2;
		ty[0] = y1;
		tx[1] = x2;
		ty[1] = y2;
		size = height / 2 + height % 2 - 1;
		tx[2] = x1;
		ty[2] = y1 + size;
		tx[3] = x1;
		ty[3] = y2 - size;

	}
	else if (dir == WA_MASK_DRAW_TRIA_RIGHT)
	{
		tx[0] = x1;
		ty[0] = y1;
		tx[1] = x1;
		ty[1] = y2;
		size = height / 2 + height % 2 - 1;
		tx[2] = x2;
		ty[2] = y1 + size;
		tx[3] = x2;
		ty[3] = y2 - size;
	}
	else if (dir == WA_MASK_DRAW_TRIA_UP)
	{
		tx[0] = x1;
		ty[0] = y2;
		tx[1] = x2;
		ty[1] = y2;
		size = width / 2 + width % 2 - 1;
		tx[2] = x1 + size;
		ty[2] = y1;
		tx[3] = x2 - size;
		ty[3] = y1;
	}
	else if (dir == WA_MASK_DRAW_TRIA_DOWN)
	{
		tx[0] = x1;
		ty[0] = y1;
		tx[1] = x2;
		ty[1] = y1;
		size = width / 2 + width % 2 - 1;
		tx[2] = x1 + size;
		ty[2] = y2;
		tx[3] = x2 - size;
		ty[3] = y2;
	}
	point[0].x = tx[0];
	point[0].y = ty[0];
	point[1].x = tx[1];
	point[1].y = ty[1];
	point[2].x = tx[3];
	point[2].y = ty[3];
	point[3].x = tx[2];
	point[3].y = ty[2];
	wa_mask_fillpolygon(point, 4, mask_p, color);
}



/**
 * display a char
 * @param x 
 * @param y	
 * @param letter
 * @param font_p
 * @param mask_p
 * @param color 
 */
void wa_mask_dispchar(int x, int y,uint32_t letter, wa_font* font_p, wa_area* mask_p, wa_gui_color color)
{
	uint8_t width;
	uint8_t* bitmap_p;
	uint8_t col,row,i;
	
	width=wa_font_get_width(font_p, letter);
	bitmap_p=wa_font_get_bitmap(font_p, letter);
	
	if((width==0)||(bitmap_p==NULL))
	{
		return;
	}
	
	for(row=0; row<font_p->height_row; row++)
	{
		for(col=0, i=7; col<width; col++, i--)
		{
			if(*bitmap_p&(1<<i))
			{
				wa_mask_drawpoint(x+col, y+row, mask_p, color);
			}
			if(i==0)
			{
				bitmap_p++;
				i=8;
			}
		}
		if(i!=7)
		{
			bitmap_p++;
		}
	}
}

/**
 * display string
 * @param area_p display area
 * @param str
 * @param font_p
 * @param row_space
 * @param col_space
 * @param mask_p
 * @param color
 */
void wa_mask_dispstr_1(wa_area* area_p, uint8_t* str, wa_font* font_p,
						uint8_t row_space, uint8_t col_space,
						wa_area* mask_p, wa_gui_color color)
{
	int x0, y0;
	int x, y;
	int letter_w, letter_h;
	uint8_t hz = 0;
	wa_area conn;

	if (str == NULL)
	{
		return;
	}
	if (font_p == NULL)
	{
		return;
	}
	if (wa_area_union(&conn, area_p, mask_p) != wa_ok)
	{
		return;
	}

	x0 = area_p->x1;
	y0 = area_p->y1;
	x = x0;
	y = y0;
	letter_h = font_p->height_row;

	while (*str != '\0')
	{
		if (hz == 0)
		{
			if (*str > 0x80)
			{
				hz = 1;
			}
			else
			{
				letter_w = wa_font_get_width(font_p, (uint32_t)(*str));
				if ((*str == '\r') || (*str == '\n'))
				{
					y += letter_h;
					y += row_space;
					x = x0;
					str++;
				}
				else
				{
					wa_mask_dispchar(x, y, (uint32_t)*str, font_p, &conn, color);
					x += letter_w;
					x += col_space;
					str++;
				}
			}
		}
		else
		{
			uint32_t letter;
			hz = 0;
			letter = (((uint32_t)(*str)) << 8) + ((uint32_t)(*(str + 1)));
			letter_w = wa_font_get_width(font_p, letter);
			wa_mask_dispchar(x, y, letter, font_p, &conn, color);
			x += letter_w;
			x += col_space;
			str += 2;
		}
	}
}

/**
 * display string
 * @param area_p display area
 * @param str 
 * @param font_p 
 * @param row_space
 * @param col_space
 * @param mask_p 
 * @param color 
 */
void wa_mask_dispstr_2(wa_area* area_p, uint8_t* str, wa_font* font_p,
										uint8_t row_space, uint8_t col_space,
										wa_area* mask_p, wa_gui_color color)
{
	int x0, y0;
	int x, y;
	int width, height;
	int letter_w, letter_h;
	uint8_t hz=0;
	
	if(str==NULL)
	{
		return;
	}
	
	if(font_p==NULL)
	{
		return;
	}
	
	x0=area_p->x1;
	y0=area_p->y1;
	x=x0;
	y=y0;
	width=area_p->x2-area_p->x1+1;
	height=area_p->y2-area_p->y1+1;
	letter_h=font_p->height_row;
	
	while(*str!='\0')
	{
		if(hz==0)
		{
			if(*str>0x80)
			{
				hz=1;
			}
			else
			{
				letter_w=wa_font_get_width(font_p,(uint32_t)(*str));
				if(x>(x0+width-letter_w))
				{
					y+=letter_h;
					y+=row_space;
					x=x0;
					if(y>(y0+height-letter_h))
					{
						break;
					}
				}
				if((*str=='\r')||(*str=='\n'))
				{
					y+=letter_h;
					y+=row_space;
					x=x0;
					if(y>(y0+height-letter_h))
					{
						break;
					}
					str++;
				}
				else
				{
					wa_mask_dispchar(x, y, (uint32_t)*str, font_p, mask_p, color);
					x+=letter_w;
					if(x>(x0+width-col_space))
					{
						y+=letter_h;
						y+=row_space;
						x=x0;
						if(y>(y0+height-letter_h))
						{
							break;
						}
					}
					else
					{
						x+=col_space;
					}
					str++;
				}
			}
		}
		else
		{
			uint32_t letter;
			hz=0;
			letter=(((uint32_t)(*str))<<8)+((uint32_t)(*(str+1)));
			letter_w=wa_font_get_width(font_p, letter);
			if(x>(x0+width-letter_w))
			{
				y+=letter_h;
				y+=row_space;
				x=x0;
				if(y>(y0+height-letter_h))
				{
					break;
				}
			}
			wa_mask_dispchar(x, y, letter, font_p, mask_p, color);
			x+=letter_w;
			if(x>(x0+width-col_space))
			{
				y+=letter_h;
				y+=row_space;
				x=x0;
				if(y>(y0+height-letter_h))
				{
					break;
				}
			}
			else
			{
				x+=col_space;
			}
			str+=2;
		}
	}
}

/**
 * draw bitmap
 * @param x
 * @param y
 * @param bitmap
 * @param mask_p
 * @param color
 */
void wa_mask_draw_bitmap(int x, int y, wa_bitmap* bitmap, wa_area* mask_p, wa_gui_color color)
{
	uint32_t row, col;
	uint32_t i;
	uint8_t* data_p;
	data_p = wa_bitmap_get_data(bitmap);

	for (row = 0; row < bitmap->height; row++)
	{
		for (col = 0, i = 7; col < bitmap->width; col++, i--)
		{
			if (*data_p & (1 << i))
			{
				wa_mask_drawpoint(x + col, y + row, mask_p, color);
			}
			if (i == 0)
			{
				data_p++;
				i = 8;
			}
		}
		if (i != 7)
		{
			data_p++;
		}
	}
}

void wa_mask_inverse_rect(int x1, int y1, int width, int height, wa_area* mask_p)
{
	int x2, y2;
	int x, y;
	x2 = x1 + width - 1;
	y2 = y1 + height - 1;
	for (x = x1; x <= x2; x++)
	{
		for (y = y1; y <= y2; y++)
		{
			wa_point p;
			p.x = x;
			p.y = y;
			if (wa_area_is_point_on(mask_p, &p) == wa_ok)
			{
				wa_gui_color color;
				color = wa_disp_drv_getpixel(x, y);
				color = ~color;
				wa_disp_drv_setpixel(x, y, color);
			}
		}
	}
}

void wa_mask_inverse_roundrect(int x1, int y1, int width, int height, int r, wa_area* mask_p)
{
	int x2;
	int min_length;
	int cx, cy;
	int hl, wl;
	int a, b;
	int di;
	int x, y;
	int x_lmax, x_rmin;
	min_length = WA_MATH_MIN(width, height);
	if (r > (min_length / 2))
	{
		r = min_length / 2;
	}
	x2 = x1 + width - 1;
	cx = x1 + r;
	cy = y1 + r;
	wl = width - 2 * r - 1;
	hl = height - 2 * r - 1;
	//fill round
	x_lmax = x1;
	x_rmin = x2;
	a = 0; b = r;
	di = 3 - (r << 1);             //a marker to determine the position of the next point
	while (a <= b)
	{
		if (a != b)
		{
			x = cx + a + wl;
			if (x < x_rmin)
			{
				x_rmin = x;
			}
			for (y = cy - b; y <= cy + b + hl; y++)
			{
				wa_point p;
				p.x = x;
				p.y = y;
				if (wa_area_is_point_on(mask_p, &p) == wa_ok)
				{
					wa_gui_color color;
					color = wa_disp_drv_getpixel(x, y);
					color = ~color;
					wa_disp_drv_setpixel(x, y, color);
				}
			}

			x = cx - a;
			if (x > x_lmax)
			{
				x_lmax = x;
			}
			if (x < x_rmin)
			{
				for (y = cy - b; y <= cy + b + hl; y++)
				{
					wa_point p;
					p.x = x;
					p.y = y;
					if (wa_area_is_point_on(mask_p, &p) == wa_ok)
					{
						wa_gui_color color;
						color = wa_disp_drv_getpixel(x, y);
						color = ~color;
						wa_disp_drv_setpixel(x, y, color);
					}
				}
			}
		}
		a++;
		//use Bresenham  
		if (di < 0)
		{
			di += 4 * a + 6;
		}
		else
		{
			di += 10 + 4 * (a - b);
			b--;

			x = cx + b + 1 + wl;
			for (y = cy - a + 1; y <= cy + a - 1 + hl; y++)
			{
				wa_point p;
				p.x = x;
				p.y = y;
				if (wa_area_is_point_on(mask_p, &p) == wa_ok)
				{
					wa_gui_color color;
					color = wa_disp_drv_getpixel(x, y);
					color = ~color;
					wa_disp_drv_setpixel(x, y, color);
				}
			}
			x = cx - b - 1;
			for (y = cy - a + 1; y <= cy + a - 1 + hl; y++)
			{
				wa_point p;
				p.x = x;
				p.y = y;
				if (wa_area_is_point_on(mask_p, &p) == wa_ok)
				{
					wa_gui_color color;
					color = wa_disp_drv_getpixel(x, y);
					color = ~color;
					wa_disp_drv_setpixel(x, y, color);
				}
			}
		}
	}
	//fill rect
	for (x = x_lmax + 1; x <= x_rmin - 1; x++)
	{
		for (y = y1; y < y1 + height; y++)
		{
			wa_point p;
			p.x = x;
			p.y = y;
			if (wa_area_is_point_on(mask_p, &p) == wa_ok)
			{
				wa_gui_color color;
				color = wa_disp_drv_getpixel(x, y);
				color = ~color;
				wa_disp_drv_setpixel(x, y, color);
			}
		}
	}
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void fp_draw_h_line(int x1, int y, int x2,wa_area* mask_p, wa_gui_color color) 
{
  wa_mask_drawline(x1,y,x2,y,mask_p,color);
}

static int fp_check_y_intersect(int y, int* px, wa_point* p_p1, wa_point* p_p2)
{
	int x1,y1,x2,y2;
	int Mul;
	if(p_p1->y<=p_p2->y)
	{
		y1=p_p1->y;
		if(y<y1)
		{
			return 0;
		}
		y2=p_p2->y;
		if(y>y2)
		{
			return 0;
		}
		x1=p_p1->x;
		x2=p_p2->x;
	}
	else
	{
		y1=p_p2->y;
		if(y<y1)
		{
			return 0;
		}
		y2=p_p1->y;
		if(y>y2)
		{
			return 0;
		}
		x1=p_p2->x;
		x2=p_p1->x;
	}
	Mul = (x2 - x1) * (y - y1);
  if(Mul > 0)
	{
		Mul += (y2 - y1) >> 1;
  }
	else
	{
		Mul -= ((y2 - y1) >> 1) - 1;
  }
  x1 += Mul / (y2 - y1);
  *px = x1;
  return 1;
}
	
static void fp_add(int x) 
{
  if (WA_FP_Cnt < WA_FP_MAXCOUNT) 
	{
    int i;
    /* Move all entries to the right (bigger x-value) */
    for (i=WA_FP_Cnt; i ; i--) 
		{
      if (_aX[i-1] < x)
			{
        break;
			}
      _aX[i] = _aX[i-1];
    }
    /* Insert new entry */
    _aX[i]    = x;
    WA_FP_Cnt++;
  }
}

static void fp_init(void) 
{
  WA_FP_Cnt = 0;
}

static void fp_flush(int y,wa_area* mask_p, wa_gui_color color) 
{
  int i, x = 0;
  char On=0;
  for (i=0; i<WA_FP_Cnt; i++) 
	{
    int xNew = _aX[i];
    if (On) 
		{
      fp_draw_h_line(x, y, xNew, mask_p, color);
    }
    On ^= 1;
    x = xNew;
  }
}

static void fp_addpoint(int x, int y, int y0, int y1, wa_area* mask_p, wa_gui_color color) 
{
  if ((y0 ^ y1) >= 0) 
	{
    fp_draw_h_line(x, y, x, mask_p, color);    /* V-point, not crossing the polygon */
  } 
	else 
	{
    fp_add(x);
  }
}

static int fp_get_prev_point_diffy(wa_point* p_p, int i,
                              int count, int y0) 
{
  int j, y1;
  for (j = 0; j < (count - 1) ; j++) 
	{
    i = (i != 0) ? i - 1 : count - 1;
    y1 = (p_p + i)->y;
    if (y1 != y0) 
		{
      return y1;
    }
  }
  return y0;
}

